home *** CD-ROM | disk | FTP | other *** search
- ##
- ## startup.s
- ##
- ## Startup code for PowerPC programs using the PowerUp kernel
- ## It saves registers, initializes _stdin, _stdout and _stderr,
- ## parses the command line and calls _main().
- ##
- ##
- ## V0.9 23-Dec-97 phx
- ## No longer expect argc/argv from ppcrun/elfrun/etc.. A command
- ## line pointer is received in r3 and must be parsed first. If no
- ## problems occur, _main() will receive argc/argv as usual. Other-
- ## wise it will get argc=argv=0.
- ## Still no WB-startup support...
- ## Fixed a bug with stderr (Enforcer-hit/IsInteractive()) in
- ## "Non-StartupMessage mode".
- ## Successfully tested with ppc.library V45.2.
- ## V0.8 21-Nov-97 phx
- ## CallOS()-fix for ppc.library V44.29 with old libamiga.a.
- ## V0.7 02-Nov-97 phx
- ## Shorter startup code by using stmw/lmw.
- ## V0.6 18-Oct-97 phx
- ## The ppc.library executes ELF objects at .text+4, so the first
- ## instruction was always skipped... :(
- ## SysBase is exported. DOSBase must be initialized by _main().
- ## V0.5 15-Oct-97 phx
- ## Also works with R.Schmidt's ppcload.
- ## Supports blr in _main(), although libvc.a jumps to _exit directly.
- ## No longer use r13 for debugging output. It's reserved for
- ## Small Data pointer in V.4. :P
- ## V0.4 13-Oct-97 phx
- ## No longer touches r2. r2 is reserved in System V.4 ABI!
- ## V0.3 07-Oct-97 phx
- ## Rewritten in pure PowerPC assembler (pasm).
- ## V0.2 04-Oct-97 phx
- ## Use "CONSOLE:" instead "*" (PowerPC will definitely not run
- ## under Kickstart 1.x :)
- ## argc and argv are passed via startup message. argc and argv are
- ## also passed in GPR3 and GPR4 but I will better read them from the
- ## startup message...
- ## When the program terminates, the result code is returned in
- ## the startup message, which is replied then.
- ## V0.1 03-Oct-97 phx
- ## created
-
-
- .set DEBUG,0 # set to 1 for serial debugging
- .set WAITBUTTON,0 # if 1, then wait for left mouse button,
- # after debugging output
- .set CALLOSFIX,1 # ppc.library V44.29 has PPCCallOS(), but
- # old libamiga.a stil uses CallOS().
-
- # powerup includes
- .set PPCTASKTAG_STARTUP_MSG,0x80020015
- .set PPCTASKTAG_STARTUP_MSGDATA,0x80020016
-
- # struct StartupData
- .set sd_M68kPort,0 # the PowerPC task can send messages to this port
- .set sd_std_in,4 # standard input handle
- .set sd_std_out,8 # standard output handle
- .set sd_std_err,12 # standard error handle
- .set sd_retCode,16 # PPC return code, passed on to M68k
- .set sd_flags,20 # additional flags (currently unused)
-
- .set IOERROR,50 # can't open stdin/stdout/stderr
-
- # serial debugging
- .if DEBUG
- .extern PPCRawDoFmt
-
- .macro _debug # _debug <format string>[,<gpr>, ...]
- .data # ... works with all GPRs, except r12
- .db\@: .string \1
- .text
- stwu r12,-4(r1)
- lis r12,.regsave@ha
- addi r12,r12,.regsave@l
- stw r0,0(r12)
- stw r3,4(r12)
- stw r4,8(r12)
- stw r5,12(r12)
- stw r6,16(r12)
- stw r7,20(r12)
- stw r8,24(r12)
- stw r9,28(r12)
- stw r10,32(r12)
- stw r11,36(r12)
- lwz r3,0(r1)
- addi r1,r1,4
- stw r3,40(r12)
- lwz r3,4(r12)
- .ifge $NARG-2
- lis r12,.datastream@ha
- addi r12,r12,.datastream@l
- stw \2,0(r12)
- .endif
- .ifge $NARG-3
- stw \3,4(r12)
- .endif
- .ifge $NARG-4
- stw \4,8(r12)
- .endif
- .ifge $NARG-5
- stw \5,12(r12)
- .endif
- .iflt $NARG-2
- li r4,0
- .else
- mr r4,r12
- .endif
- lis r3,(.db\@)@ha
- addi r3,r3,(.db\@)@l
- li r5,1
- li r6,0
- bl PPCRawDoFmt # output to serial line
- .if WAITBUTTON
- lis r12,0xbfe001@h # wait for left mouse button
- ori r12,r12,0xbfe001@l
- .dbwait1\@:
- lbz r3,0(r12)
- andi. r3,r3,0x40
- bne .dbwait1\@
- .dbwait2\@:
- lbz r3,0(r12)
- andi. r3,r3,0x40
- beq .dbwait2\@
- .endif
- lis r12,.regsave@ha
- addi r12,r12,.regsave@l
- lwz r0,0(r12)
- lwz r3,4(r12)
- lwz r4,8(r12)
- lwz r5,12(r12)
- lwz r6,16(r12)
- lwz r7,20(r12)
- lwz r8,24(r12)
- lwz r9,28(r12)
- lwz r10,32(r12)
- lwz r11,36(r12)
- lwz r12,40(r12)
- .endm
-
- .else
- .macro _debug
- .endm
- .endif
-
-
- .text
-
- .extern _main
- .extern PPCGetTaskAttr
- .extern PPCOpen
- .extern PPCClose
- .extern PPCAllocVec
- .extern PPCFreeVec
-
-
- # This is the first function in a program. Execution starts here!
-
- __start:
- nop # ppc.library bug fix
- stwu r1,-448(r1)
- mflr r11
- stw r11,452(r1)
- stmw r14,224(r1) # save all non-volatile registers
- stfd f14,296(r1)
- stfd f15,304(r1)
- stfd f16,312(r1)
- stfd f17,320(r1)
- stfd f18,328(r1)
- stfd f19,336(r1)
- stfd f20,344(r1)
- stfd f21,352(r1)
- stfd f22,360(r1)
- stfd f23,368(r1)
- stfd f24,376(r1)
- stfd f25,384(r1)
- stfd f26,392(r1)
- stfd f27,400(r1)
- stfd f28,408(r1)
- stfd f29,416(r1)
- stfd f30,424(r1)
- stfd f31,432(r1)
- _debug "\n-------\nstartup\n-------\nstack = 0x%08lx\n",r1
- lis r11,_init_stk@ha # save initial stack pointer
- stw r1,_init_stk@l(r11)
-
- li r14,0 # r14: argc = 0
- mr. r15,r3 # r15: command line/argv
- bnel parse_args
- lis r16,.constring@ha # r16 = "CONSOLE:"
- addi r16,r16,.constring@l
-
- # initialize SysBase
- li r3,4
- lwz r0,0(r3)
- lis r3,SysBase@ha
- stw r0,SysBase@l(r3)
-
- # evaluate startup message from M68k
- lis r3,PPCTASKTAG_STARTUP_MSG@h
- ori r3,r3,PPCTASKTAG_STARTUP_MSG@l
- bl PPCGetTaskAttr
- _debug "PPCTASKTAG_STARTUP_MSG = 0x%08lx\n",r3
- cmpwi r3,0
- beq .1
- lis r3,PPCTASKTAG_STARTUP_MSGDATA@h
- ori r3,r3,PPCTASKTAG_STARTUP_MSGDATA@l
- bl PPCGetTaskAttr
- _debug "PPCTASKTAG_STARTUP_MSGDATA = 0x%08lx\n",r3
- lwz r4,sd_std_in(r3) # get _stdin
- lis r11,_stdin@ha
- stw r4,_stdin@l(r11)
- lwz r5,sd_std_out(r3) # get _stdout
- lis r11,_stdout@ha
- stw r5,_stdout@l(r11)
- lwz r6,sd_std_err(r3) # get _stderr
- lis r11,_stderr@ha
- stw r6,_stderr@l(r11)
- lis r11,_startup_data@ha
- stw r3,_startup_data@l(r11)
- _debug "stdin=0x%08lx stdout=0x%08lx stderr=0x%08lx\n",r4,r5,r6
- b .startup
-
- # get _stdin, _stdout, _stderr
- .1: li r4,1005
- mr r3,r16
- bl PPCOpen # PPCOpen("CONSOLE:",MODE_OLDFILE)
- _debug "PPCOpen(\"%s\",MODE_OLDFILE) = 0x%08lx\n",r16,r3
- cmpwi r3,0
- beq __exit
- lis r11,_stdin@ha
- stw r3,_stdin@l(r11)
-
- li r4,1006
- mr r3,r16
- bl PPCOpen # PPCOpen("CONSOLE:",MODE_NEWFILE)
- _debug "PPCOpen(\"%s\",MODE_NEWFILE) = 0x%08lx\n",r16,r3
- cmpwi r3,0
- beq __exit
- lis r11,_stdout@ha
- stw r3,_stdout@l(r11)
- lis r12,_stderr@ha
- stw r3,_stderr@l(r12) # _stderr = _stdout
-
- # call _main in libvc.a
- .startup:
- mr r3,r14
- mr r4,r15
- _debug "calling _main(argc=%ld,argv=0x%08lx)\n",r3,r4
- bl _main # _main(argc,argv)
- li r3,0
- b _exit
-
- .type __start,@function
- .size __start,$-__start
-
- .constring:
- .string "CONSOLE:"
- .align 2
-
-
- __exit:
- li r3,IOERROR # error: can't open stdin/stdout
-
-
- .global _exit
- _exit:
- # r3 = return code
- mr r14,r3
- _debug "\n-----\n_exit\n-----\nstack = 0x%08lx\nrc = %ld\n",r1,r14
- # free argv
- lis r11,_argv@ha
- lwz r3,_argv@l(r11)
- bl PPCFreeVec
-
- lis r15,_startup_data@ha
- lwz r15,_startup_data@l(r15)
- cmpwi r15,0 # did we receive a startup message?
- bne .3
-
- # close _stdout
- lis r11,_stdout@ha
- lwz r3,_stdout@l(r11)
- cmpwi r3,0
- beq .2
- _debug "PPCClose(stdout=0x%08lx)\n",r3
- bl PPCClose
-
- # close _stdin
- .2: lis r11,_stdin@ha
- lwz r3,_stdin@l(r11)
- cmpwi r3,0
- beq .4
- _debug "PPCClose(stdin=0x%08lx)\n",r3
- bl PPCClose
- b .4
-
- # write return code to startup message
- .3: _debug "store rc=%ld in startup data (0x%08lx)\n",r14,r15
- stw r14,sd_retCode(r15)
-
- # restore initial stack frame
- .4: mr r3,r14
- lis r11,_init_stk@ha
- lwz r1,_init_stk@l(r11)
- lmw r14,224(r1)
- lfd f14,296(r1)
- lfd f15,304(r1)
- lfd f16,312(r1)
- lfd f17,320(r1)
- lfd f18,328(r1)
- lfd f19,336(r1)
- lfd f20,344(r1)
- lfd f21,352(r1)
- lfd f22,360(r1)
- lfd f23,368(r1)
- lfd f24,376(r1)
- lfd f25,384(r1)
- lfd f26,392(r1)
- lfd f27,400(r1)
- lfd f28,408(r1)
- lfd f29,416(r1)
- lfd f30,424(r1)
- lfd f31,432(r1)
- lwz r11,452(r1)
- mtlr r11
- addi r1,r1,448
- blr
-
- .type _exit,@function
- .size _exit,$-__exit
-
-
- .if CALLOSFIX
- .extern PPCCallOS
- .global CallOS
- CallOS:
- b PPCCallOS
-
- .type CallOS,@function
- .size CallOS,$-CallOS
- .endif
-
-
- parse_args:
- # Parse command line and generate argc/argv.
- # r14: argc=0
- # r15: cmdline (0-terminated, includes program name), will become argv
- mflr r11
- mr r10,r15
- li r12,0
- .pa1: bl nextarg
- cmpwi r3,0
- beq .pa2
- addi r12,r12,4 # another argv slot
- bl skiparg
- cmpwi r3,0
- bne .pa1
- .pa2: cmpwi r12,0
- beq .pa_nomem # no arguments found?
- addi r12,r12,4 # + one termination slot
- sub r3,r10,r15
- add r3,r3,r12
- li r4,0 # MEMF_ANY
- bl PPCAllocVec # memory for argv slots and buffer
- mr r10,r15
- mr. r15,r3
- beq .pa_nomem
- lis r9,_argv@ha
- stw r15,_argv@l(r9)
- subi r9,r15,4 # r9 argv slots
- add r12,r15,r12 # r12 argv buffer
- .pa4: bl nextarg
- cmpwi r3,0
- beq .pa_quit
- stwu r12,4(r9) # store arg-pointer
- addi r14,r14,1 # increment argc
- cmpwi r3,0x22
- bne .pa10 # quoted?
- .pa5: lbzu r3,1(r10)
- cmpwi r3,0x22
- bne .pa6
- addi r10,r10,1 # end quote
- li r3,0
- .pa6: cmpwi r3,'*' # BCPL escape character?
- bne .pa8
- lbzu r3,1(r10)
- andi. r4,r3,0xdf
- cmpwi r4,'N' # newline
- bne .pa7
- li r3,10
- .pa7: cmpwi r4,'E' # escape
- bne .pa8
- li r3,27
- .pa8: stb r3,0(r12)
- addi r12,r12,1
- cmpwi r3,0
- bne .pa5
- b .pa4
- .pa10: stb r3,0(r12) # normal arg copy
- addi r12,r12,1
- lbzu r3,1(r10)
- cmplwi r3,0x20
- bgt .pa10
- li r3,0
- b .pa8
-
- .pa_nomem:
- li r15,0
- mtlr r11
- blr
- .pa_quit:
- stwu r3,4(r9) # r3=0 terminates the arguments
- mtlr r11
- blr
-
- .type parse_args,@function
- .size parse_args,$-parse_args
-
-
- nextarg:
- # move pointer to beginning of next argument
- # r10: cmdline-pointer
- # -> r10: new cmdline-pointer, r3: char
- lbz r3,0(r10)
- cmplwi r3,0x20
- bgtlr
- cmpwi r3,0
- beqlr
- addi r10,r10,1
- b nextarg
-
- .type nextarg,@function
- .size nextarg,$-nextarg
-
-
- skiparg:
- # move pointer behind the current argument
- # r10: cmdline-pointer
- # -> r10: new cmdline-pointer, r3: char
- lbz r3,0(r10)
- cmpwi r3,0x22 # " ?
- beq .skipquote
- .sk1: cmplwi r3,0x20
- blelr
- cmpwi r3,0
- beqlr
- lbzu r3,1(r10)
- b .sk1
- .skipquote:
- lbzu r3,1(r10)
- cmpwi r3,0
- beqlr
- cmpwi r3,'*' # escape?
- bne .sk2
- lbzu r4,1(r10)
- cmpwi r4,0
- beqlr
- .sk2: cmpwi r3,0x22 # " ?
- bne .skipquote
- lbzu r3,1(r10)
- blr
-
- .type skiparg,@function
- .size skiparg,$-skiparg
-
-
-
- .type _init_stk,@object
- .size _init_stk,4
- .bss _init_stk,4
-
- .type _startup_data,@object
- .size _startup_data,4
- .bss _startup_data,4
-
- .type _argv,@object
- .size _argv,4
- .bss _argv,4
-
- .global _stdin
- .type _stdin,@object
- .size _stdin,4
- .comm _stdin,4
-
- .global _stdout
- .type _stdout,@object
- .size _stdout,4
- .comm _stdout,4
-
- .global _stderr
- .type _stderr,@object
- .size _stderr,4
- .comm _stderr,4
-
- .global SysBase
- .type SysBase,@object
- .size SysBase,4
- .comm SysBase,4
-
- .if DEBUG
- .bss .regsave,11*4 # r0,r3,...,r12
- .bss .datastream,4*4 # max. 4 arguments
- .endif
-